package cn.fzkj.framework.aop;

import cn.fzkj.common.ResultCode;
import cn.fzkj.common.ResultVO;
import cn.fzkj.framework.annotation.Authentication;
import cn.fzkj.common.constant.AuthCons;
import cn.fzkj.framework.exception.client.ClientErrorCode;
import cn.fzkj.framework.exception.client.ClientException;
import cn.fzkj.framework.redis.utils.RedisUtil;
import cn.fzkj.project.user.domain.User;
import cn.fzkj.project.user.mapper.UserMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
public class AuthenticationAspect {
    public final static Logger log = LoggerFactory.getLogger(AuthenticationAspect.class);

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserMapper userMapper;

    @Pointcut(value = "@annotation(cn.fzkj.framework.annotation.Authentication)")
    public void pointcut() {
    }

    @AfterReturning(returning = "result", value = "@annotation(cn.fzkj.framework.annotation.Authentication)")
    public void after(JoinPoint joinPoint, Object result) {
        log.error("处理玩了，返回值：{}", result);
    }

    /**
     *
     * @param proceedingJoinPoint
     * @param authentication  方法上的注解，可以拿到访问该方法需要的身份
     * @return
     */
    @Around("pointcut() && @annotation(authentication)")
    public Object interceptor(ProceedingJoinPoint proceedingJoinPoint, Authentication authentication) {
        // 拿到方法上标注的访问需要的身份
        // 因为我想的是必须登录，所以就需要一个用户和管理员，
        // 但是登录之后必是用户，所以就只需要在管理员权限的方法上加注解，验证是否有管理员权限
        AuthCons role = authentication.role();
        // 先拿到token，去判断是什么身份
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
        String token = request.getHeader("token");
        if (null == token) throw new ClientException(ClientErrorCode.Code.TOKEN_NOT_FIND);
        AuthCons realRole = authenticate(token);
        if (realRole == AuthCons.ADMIN){
            try {
                log.error("权限正确");
                return proceedingJoinPoint.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
        return ResultVO.failure(ResultCode.ACCESS_FORBIDDEN);
    }

    /**
     * 这个方法用于判断该token所属的到底是谁(管理员？)
     * @param token
     * @return
     */
    private AuthCons authenticate(String token) {
        // 去redis中，拿到token
        // redis存 token:用户真实名
        // 拿到真实名字取数据库查身份
        String realName = "";
        try{
            realName = String.valueOf(redisUtil.get(token));// 拿到真实名字
            log.error("redis中拿到的名字：{}", realName);
        }catch (Exception e){
            log.error("token已失效 == > {}", e.getMessage());
            return null;
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_real_name", realName);
        User user = userMapper.selectList(queryWrapper).get(0);
        return user.getUserType() == 1 ? AuthCons.ADMIN : AuthCons.USER;
    }

}
